package main

import (
	"fmt"
	"os"

	"github.com/spf13/pflag"
	"strings"
)

const (
	RunMode_Server = iota
	RunMode_Client
	RunMode_Console
)

type ServerConfig struct {
	KeySetPath string
	ListenAddr string
}

func printErr(err error, msg string) {
	fmt.Println("Error:", msg)
	fmt.Printf("    %v\n", err)
}

func printUsage() {
	fmt.Println("Usage:\n  keytool console|client|server|stop [ARGUMENT]... [OPTION]...\n")
	fmt.Println("Type 'keytool help <SUB-COMMAND>' to get sub-command usage information.")
}

func help(what string, flags *pflag.FlagSet) {
	what = strings.ToLower(what)
	if what == "console" {
		fmt.Println("Usage:\n  keytool console <KEYSET>")
		fmt.Println("Description:")
		fmt.Println("  Run keytool in console mode. KEYSET is the path of keyset file.")
	} else if what == "client" {
		fmt.Println("Usage:\n  keytool client <RADDR>")
		fmt.Println("Description:")
		fmt.Println("  Run keytool in client mode. RADDR is the TCP address of a keytool server to")
		fmt.Println("  connect.")
	} else if what == "server" {
		fmt.Println("Usage:\n  keytool server [OPTION]...")
		fmt.Println("Description:\n  Run keytool in server mode.")
		fmt.Println("Options:")
		flags.PrintDefaults()
	} else if what == "stop" {
		fmt.Println("Usage:\n  keytool stop [PID]")
		fmt.Println("Description:")
		fmt.Println("  Stop the running keytool server. if PID which is the process id of a running")
		fmt.Println("  keytool server process is specified, a SIGTERM signal will be sent to that")
		fmt.Println("  process. Otherwise, the running keytool server process will be found and ")
		fmt.Println("  terminated automatically.")
	} else {
		fmt.Printf("Error: Unknown sub-command '%s'\n", what)
	}
}

func main() {
	/*
	 * 必须至少指定一个子命令。
	 */
	if len(os.Args) < 2 {
		fmt.Println("Error: No sub-command is specified.")
		printUsage()
		os.Exit(1)
	}

	sconf := &ServerConfig{}

	sflags := pflag.NewFlagSet("", pflag.ContinueOnError)
	sflags.SetOutput(os.Stdout)
	sflags.StringVarP(&sconf.KeySetPath, "keyset", "k", "", "Keyset file path. Defaults to current directory.")
	sflags.StringVarP(&sconf.ListenAddr, "listen-addr", "l", "", "TCP address to listen on.")

	subcmd := strings.ToLower(os.Args[1])
	switch subcmd {
	case "client":
		if len(os.Args) < 3 {
			fmt.Println("Error: Remote address is not specified.")
			os.Exit(1)
		}
		RunAsClient(os.Args[2])

	case "console":
		if len(os.Args) < 3 {
			fmt.Println("Error: Keyset file path is not specified.")
			os.Exit(1)
		}
		RunAsConsole(os.Args[2])

	case "server":
		if err := sflags.Parse(os.Args[2:]); err != nil {
			fmt.Println("Error: Invalid command line arguments.")
			help(subcmd, sflags)
			os.Exit(1)
		}
		RunAsServer(sconf)

	case "help":
		if len(os.Args) < 3 {
			fmt.Println("Error: No sub-command is specified.")
			os.Exit(1)
		}
		help(os.Args[2], sflags)
	}
}
